export default class Websocket {
    // 是否支持websocket
    private readonly hasWebsocket: any;
    // 转接地址
    private readonly connectUrl: string;
    // websocket对象
    private socketTask: any;
    // 断开后是否允许重连
    private resume: boolean;
    // 重连开关
    private relocal: boolean;
    // 重连定时器id
    private retimer: any;
    // 重连间隔时间
    private readonly retimeout: number;
    // 重连次数
    private renum: number;
    // 最大重连次数，-1 代表无限制
    private readonly remax: number;
    // 是否开启心跳检测
    private readonly checkcont: boolean;
    // 心跳检测发送的值
    private readonly checkcontSendValue: any;
    // 心跳定时器id
    private checkcontimer: any;
    // 心跳间隔时间
    private readonly checkcontimeout: number;
    // 是否开心debug调试
    private readonly debug: boolean;
    // 是否连接中...
    private connecting: boolean;
    // 是否打开状态
    private isOpen: boolean;

    constructor(url: string, options: any) {
        console.log('new Websocket constructor');
        this.hasWebsocket = window.WebSocket && window.WebSocket.prototype.send;
        this.connectUrl = url;
        this.socketTask = null;
        this.resume = options && options.resure ? options.resure : true;
        this.relocal = false;
        this.retimer = 0;
        this.retimeout = options && options.retimeout ? 1000 * options.retimeout : 1000 * 15;
        this.renum = 0;
        this.remax = options && options.remax ? options.remax : -1;
        this.checkcont = options && options.checkcont ? options.checkcont : true;
        this.checkcontSendValue = options && options.checkcontSendValue ? options.checkcontSendValue : {'topic': 'heartbeat'};
        this.checkcontimer = 0;
        this.checkcontimeout = options && options.checkcontimeout ? 1000 * options.checkcontimeout : 1000 * 15;
        this.debug = options && options.debug ? options.debug : false;
        this.connecting = false;
        this.isOpen = false;
    }

    public open(): void {
        this.close();
        this.initWebsocket();
    }

    public close(): void {
        if (!this.socketTask) return;
        this.socketTask.close();
        this.socketTask = null;
        this.resume = false;
        this.clear();
    }

    /**
     * 连接成功回调
     */
    public onConnectSuccess(): void {

    }

    /**
     * 关闭回调
     */
    public onClose(): void {

    }

    public onMessage(data: any): void {

    }

    public send(msg: any): void {
        if (!this.isOpen) {
            this.log('请先调用 open() 开启网络');
            return;
        }
        this.socketTask.send(JSON.stringify(msg));
    }

    /**
     * 初始化websocket
     * @private
     */
    private initWebsocket(): void {
        // 判断状态是否进行连接websocket，创建连接后，不在创建新的连接
        if (this.connecting || this.isOpen) return;
        this.connecting = true;
        this.isOpen = false;
        if (this.hasWebsocket) {   // 支持websocket
            // url.slice(0,5)==='https'?'wss + url.slice(5) : 'ws' + url.slice(4)
            console.log('new WebSocket');
            this.socketTask = new WebSocket(this.connectUrl);
            if (this.socketTask) this.connecting = false;
            this.socketTask.onopen = () => {
                console.log('---websocket连接成功---');
                this.isOpen = true;
                this.renum = 0;
                this.resume = true;
                this.onConnectSuccess();
                this.checkConnect();
            };

            this.socketTask.onmessage = (res: any): void => {
                this.getMessage(res);
                this.checkConnect();
            };

            this.socketTask.onerror = (error: any): void => {
                console.log('---websocket进入onerror回调，连接失败---：', error);
                this.isOpen = false;
                this.socketTask = null;
                this.reconnect();
            };

            this.socketTask.onclose = () => {
                console.log('---websocket进入onclose回调，表示已关闭---');
                this.isOpen = false;
                this.socketTask = null;
                this.reconnect();
                this.onClose();
            };
        } else { // 不支持websocket
            console.warn('浏览器版本过低，不支持websocket');
        }
    }

    private log(msg: string, res?: any): void {
        if (this.debug) {
            if (res) {
                console.log(msg, res);
            } else {
                console.log(msg);
            }
        }
    }

    private getMessage(res: any): void {
        try {
            const resultObj: any = JSON.parse(res.data);
            this.onMessage(resultObj);
        } catch (e: any) {
            console.error('返回数据出现异常：', e);
            this.onMessage(res);
        }
    }

    private reconnect(): void {
        if (this.relocal || !this.resume) return;
        this.relocal = true;
        this.log('开始重连...');
        this.clear();
        this.renum++;
        if (this.remax > -1 && this.renum >= this.remax) return;
        this.retimer = setTimeout((): void => {
            this.initWebsocket();
            this.relocal = false;
        }, this.retimeout);
    }

    private checkConnect(): void {
        if (!this.socketTask || !this.checkcont) return;
        this.clear();
        this.checkcontimer = setInterval((): void => {
            this.log('心跳检测...');
            this.socketTask.send(JSON.stringify(this.checkcontSendValue));
        }, this.checkcontimeout);
    }

    private clear(): void {
        this.checkcontimer && clearInterval(this.checkcontimer);
        this.retimer && clearTimeout(this.retimer);
    }
}